#include <linux/kernel.h>
#include <linux/completion.h>
#include <linux/limits.h>
#include <linux/export.h>
#include <linux/sched.h>
#include <linux/sched/signal.h>

#define complete_acquire(x)
#define complete_release(x)

static void complete_with_flags(struct completion *x, int wake_flags)
{
    unsigned long flags;

    raw_spin_lock_irqsave(&x->wait.lock, flags);

    if (x->done != UINT_MAX)
        x->done++;
    swake_up_locked(&x->wait, wake_flags);
    raw_spin_unlock_irqrestore(&x->wait.lock, flags);
}

static long do_wait_for_common(struct completion *x,
                               long (*action)(int), int timeout, int state)
{
    if (!x->done)
    {
        DECLARE_SWAITQUEUE(wait);

        do
        {
            if (signal_pending_state(state, wait.task))
            {
                timeout = -ERESTARTSYS;
                break;
            }

            __prepare_to_swait(&x->wait, &wait);
            __set_current_state(state);
            raw_spin_unlock_irq(&x->wait.lock);
            timeout = action(timeout);
            raw_spin_lock_irq(&x->wait.lock);
        } while (!x->done && timeout);

        __finish_swait(&x->wait, &wait);
        if (!x->done)
            return timeout;
    }

    if (x->done != UINT_MAX)
        x->done--;

    return timeout ?: 1;
}

static inline long __wait_for_common(struct completion *x,
                                     long (*action)(int), int timeout, int state)
{
    might_sleep();

    complete_acquire(x);

    raw_spin_lock_irq(&x->wait.lock);
    timeout = do_wait_for_common(x, action, timeout, state);
    raw_spin_unlock_irq(&x->wait.lock);

    complete_release(x);

    return timeout;
}

static long wait_for_common(struct completion *x, int timeout, int state)
{
    return __wait_for_common(x, schedule_timeout, timeout, state);
}

/********************************************************************/

/**
 * complete: - signals a single thread waiting on this completion
 * @x:  holds the state of this particular completion
 *
 * This will wake up a single thread waiting on this completion. Threads will be
 * awakened in the same order in which they were queued.
 *
 * See also complete_all(), wait_for_completion() and related routines.
 *
 * If this function wakes up a task, it executes a full memory barrier before
 * accessing the task state.
 */
void complete(struct completion *x)
{
    complete_with_flags(x, 0);
}
EXPORT_SYMBOL(complete);

bool completion_done(struct completion *x)
{
    return x->done;
}

/**
 * wait_for_completion: - waits for completion of a task
 * @x:  holds the state of this particular completion
 *
 * This waits to be signaled for completion of a specific task. It is NOT
 * interruptible and there is no timeout.
 *
 * See also similar routines (i.e. wait_for_completion_timeout()) with timeout
 * and interrupt capability. Also see complete().
 */
void wait_for_completion(struct completion *x)
{
    wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_UNINTERRUPTIBLE);
}
